package com.xhh.reapply.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.utils.thread.ThreadLocalUtil;
import com.xhh.apis.adjust.IAdjustClient;
import com.xhh.apis.check.ICheckClient;
import com.xhh.apis.user.IUserClient;
import com.xhh.common.constants.CheckedConstants;
import com.xhh.common.constants.ReapplyConstants;
import com.xhh.model.adjust.dtos.GetAdjustDto;
import com.xhh.model.adjust.pojos.Adjustment;
import com.xhh.model.adjust.pojos.Faulty;
import com.xhh.model.adjust.pojos.Major;
import com.xhh.model.check.vos.CheckedVo;
import com.xhh.model.common.dtos.ResponseResult;
import com.xhh.model.common.enums.AppHttpCodeEnum;
import com.xhh.model.reapply.dtos.AddChoiceDto;
import com.xhh.model.reapply.dtos.FiltrateStudentDto;
import com.xhh.model.reapply.dtos.GetRuleDto;
import com.xhh.model.reapply.dtos.UpdateChoiceDto;
import com.xhh.model.reapply.pojos.Reapply;
import com.xhh.model.reapply.pojos.Rule;
import com.xhh.model.reapply.pojos.Score;
import com.xhh.model.user.pojos.Student;
import com.xhh.model.user.pojos.User;
import com.xhh.reapply.mapper.ReapplyMapper;
import com.xhh.reapply.service.IRuleService;
import com.xhh.reapply.service.IScoreService;
import com.xhh.reapply.service.ReapplyService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

@Service
@RequiredArgsConstructor
public class ReapplyServiceImpl extends ServiceImpl<ReapplyMapper, Reapply> implements ReapplyService {

    private final ICheckClient checkClient;
    private final IAdjustClient adjustClient;
    private final IUserClient userClient;
    private final IRuleService ruleService;
    private final IScoreService scoreService;

    /**
     * 添加调剂志愿
     * @param dto
     * @return
     */
    @Transactional
    @Override
    public ResponseResult addChoice(AddChoiceDto dto) {
        // 1. 判断用户是否为学生，如果是学生，查询学生表获取学生手机号和考生号
        // 1.1 获取登录用户id
        User user = ThreadLocalUtil.getUser();
        Long userId = user.getId();
        // 1.2 判断用户身份类型
        ResponseResult response = checkClient.checkIdentity(userId);
        String json = (String) response.getData();
        CheckedVo checked = JSONObject.parseObject(json, CheckedVo.class);
        if (!checked.getIdentityCode().equals(CheckedConstants.STUDENT_IDENTITY_CODE)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH);
        }
        // 2. 添加志愿
        // 志愿一
        if (StrUtil.isNotEmpty(dto.getUnityCode1())) {
            // 查询缺额信息是否存在，且状态码是否不为501
            GetAdjustDto getAdjustDto = new GetAdjustDto();
            getAdjustDto.setUnityCode(dto.getUnityCode1());
            getAdjustDto.setFaultyCode(dto.getFaultyCode1());
            getAdjustDto.setMajorCode(dto.getMajorCode1());
            if (isAdjustmentNotExit(getAdjustDto)) return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,
                    "志愿一暂无缺额信息");
            // 是否满足调剂要求
            if (isAdequate(dto.getUnityCode1(), dto.getFaultyCode1(), dto.getMajorCode1(), dto.getStuCode()))
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "志愿一不符合调剂要求");
            // 添加志愿
            Reapply choice1 = new Reapply();
            choice1.setStuCode(dto.getStuCode());
            choice1.setStuName(dto.getStuName());
            choice1.setPhone(dto.getPhone1());
            choice1.setChoiceUnityCode(dto.getUnityCode1());
            choice1.setChoiceFaultyCode(dto.getFaultyCode1());
            // 根据院系编码获取院系名称
            Faulty faulty1 = getFauByCode(dto.getFaultyCode1());
            choice1.setChoiceFaultyName(faulty1.getFaultyName());
            choice1.setChoiceMajorCode(dto.getMajorCode1());
            // 根据专业编码获取专业名称
            Major major1 = getMajorByCode(dto.getMajorCode1());
            choice1.setChoiceMajorName(major1.getMajorName());
            choice1.setStatus(ReapplyConstants.ADD_SUCCESS_CHOICE_STATUS);
            choice1.setCreateTime(new Date());
            save(choice1);
        }
        // 志愿二
        if (StrUtil.isNotEmpty(dto.getMajorCode2())) {
            GetAdjustDto getAdjustDto2 = new GetAdjustDto();
            getAdjustDto2.setUnityCode(dto.getUnityCode2());
            getAdjustDto2.setFaultyCode(dto.getFaultyCode2());
            getAdjustDto2.setMajorCode(dto.getMajorCode2());
            if (isAdjustmentNotExit(getAdjustDto2)) return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,
                    "志愿二暂无缺额信息");
            // 是否满足调剂要求
            if (isAdequate(dto.getUnityCode2(), dto.getFaultyCode2(), dto.getMajorCode2(), dto.getStuCode()))
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "志愿二不符合调剂要求");
            // 添加志愿
            Reapply choice2 = new Reapply();
            choice2.setStuCode(dto.getStuCode());
            choice2.setStuName(dto.getStuName());
            choice2.setPhone(dto.getPhone2());
            choice2.setChoiceUnityCode(dto.getUnityCode2());
            choice2.setChoiceFaultyCode(dto.getFaultyCode2());
            // 根据院系编码获取院系名称
            Faulty faulty2 = getFauByCode(dto.getFaultyCode2());
            choice2.setChoiceFaultyName(faulty2.getFaultyName());
            choice2.setChoiceMajorCode(dto.getMajorCode2());
            // 根据专业编码获取专业名称
            Major major2 = getMajorByCode(dto.getMajorCode2());
            choice2.setChoiceMajorName(major2.getMajorName());
            choice2.setStatus(ReapplyConstants.ADD_SUCCESS_CHOICE_STATUS);
            choice2.setCreateTime(new Date());
            save(choice2);
        }
        // 3. 封装结果返回
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 判断是否满足调剂要求
     * @param unityCode
     * @param faultyCode
     * @param majorCode
     * @param StuCode
     * @return
     */
    private boolean isAdequate(String unityCode, String faultyCode, String majorCode, String StuCode) {
        GetRuleDto ruleDto = new GetRuleDto(unityCode, faultyCode, majorCode);
        ResponseResult result = ruleService.getRuleByUCodeFCodeAndCode(ruleDto);
        String s = JSON.toJSONString(result.getData());
        Rule rule = JSONObject.parseObject(s, Rule.class);
        Score score = scoreService.lambdaQuery()
                .eq(Score::getStuCode, StuCode)
                .eq(Score::getZzllCode, rule.getZzllCode())
                .gt(Score::getZzllScore, rule.getZzllScore())
                .eq(Score::getWgyCode, rule.getWgyCode())
                .gt(Score::getWgyScore, rule.getWgyScore())
                .eq(Score::getYwk1Code, rule.getYwk1Code())
                .gt(Score::getYwk1Score, rule.getYwk1Score())
                .eq(Score::getYwk2Code, rule.getYwk2Code())
                .gt(Score::getYwk2Score, rule.getYwk2Score())
                .gt(Score::getTotal, rule.getTotal())
                .one();
        if (score == null) {
            return true;
        }
        return false;
    }

    /**
     * 判断缺额信息是否存在
     * @param getAdjustDto
     * @return
     */
    private boolean isAdjustmentNotExit(GetAdjustDto getAdjustDto) {
        ResponseResult responseResult = adjustClient.getAdjustByCode(getAdjustDto);
        if (!responseResult.getCode().equals(200) || responseResult.getData() == null) {
            return true;
        }
        return false;
    }

    /**
     * 学生用户查看调剂志愿
     * @param stuId
     * @return
     */
    @Override
    public ResponseResult getChoice(Long stuId) {
        // 1. 校验参数
        if (stuId == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        User user = ThreadLocalUtil.getUser();
        // 2. 构建查询条件
        // 2.1 校验用户身份，如果是学生用户则查询学生表
        ResponseResult response = checkClient.checkIdentity(user.getId());
        String json = (String) response.getData();
        CheckedVo checked = JSONObject.parseObject(json, CheckedVo.class);
        if (!checked.getIdentityCode().equals(CheckedConstants.STUDENT_IDENTITY_CODE)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH);
        }
        ResponseResult result = userClient.getStuById(stuId);
        String stuJson = JSON.toJSONString(result.getData());
        Student student = JSONObject.parseObject(stuJson, Student.class);
        // 2.2 根据学生的准考证号查询调剂志愿表
        List<Reapply> reapplies = lambdaQuery()
                .eq(Reapply::getStuCode, student.getStuNo())
                .list();
        if (CollUtil.isEmpty(reapplies)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "暂无调剂志愿");
        }
        // 3. 返回结果
        return ResponseResult.okResult(reapplies);
    }

    /**
     * 修改志愿
     * @param dto
     * @return
     */
    @Override
    public ResponseResult updateChoice(UpdateChoiceDto dto) {
        // 1. 校验参数
        if (dto == null || dto.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 2. 更新志愿
        // 2.1 根据id查询志愿信息
        Reapply choice = getById(dto.getId());
        if (choice == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        // 2.2 判断填报志愿的时间是否超过48小时，只有超过48小时才允许修改
        // 志愿填报时间
        Calendar createTime = Calendar.getInstance();
        createTime.setTime(choice.getCreateTime());
        // 当前时间
        Date now = new Date();
        Calendar currentTime = Calendar.getInstance();
        currentTime.setTime(now);
        // 相差时间
        long sub = currentTime.getTimeInMillis() - createTime.getTimeInMillis();
        if ((sub / (60 * 60 * 1000)) < 48) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_OVER_48_HOUR);
        }
        // 2.3 修改志愿
        // 判断要修改的志愿是否有缺额信息
        GetAdjustDto getAdjustDto = new GetAdjustDto();
        getAdjustDto.setUnityCode(dto.getUnityCode());
        getAdjustDto.setFaultyCode(dto.getFaultyCode());
        getAdjustDto.setMajorCode(dto.getMajorCode());
        if (isAdjustmentNotExit(getAdjustDto)) return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,
                "志愿暂无缺额信息");
        // 是否满足调剂要求
        if (isAdequate(dto.getUnityCode(), dto.getFaultyCode(), dto.getMajorCode(), choice.getStuCode()))
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "不符合调剂要求");
        // 修改志愿
        Reapply reapply = BeanUtil.copyProperties(dto, Reapply.class);
        // 院系名称
        Faulty faulty = getFauByCode(dto.getFaultyCode());
        reapply.setChoiceMajorName(faulty.getFaultyName());
        // 专业名称
        Major major = getMajorByCode(dto.getMajorCode());
        reapply.setChoiceMajorName(major.getMajorName());
        // 更新时间
        reapply.setUpdateTime(now);
        updateById(reapply);
        // 3. 返回结果
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 根据院系编码获取院系名称
     * @param faultyCode
     * @return
     */
    private Faulty getFauByCode(String faultyCode) {
        ResponseResult responseResult = adjustClient.getFaultyByCode(faultyCode);
        String fauStr = JSON.toJSONString(responseResult.getData());
        return JSONObject.parseObject(fauStr, Faulty.class);
    }

    /**
     * 根据专业编码获取专业信息
     * @param majorCode
     * @return
     */
    private Major getMajorByCode(String majorCode) {
        ResponseResult responseResult = adjustClient.getMajorByCode(majorCode);
        String fauStr = JSON.toJSONString(responseResult.getData());
        return JSONObject.parseObject(fauStr, Major.class);
    }
}
